/*
 * @lc app=leetcode.cn id=641 lang=golang
 *
 * [641] 设计循环双端队列
 */

// @lc code=start
type MyCircularDeque struct {
	queue      []int
	capability int
	left       int
	right      int
}

func Constructor(k int) MyCircularDeque {
	return MyCircularDeque{
		make([]int, k), k, 0, 0,
	}
}

func (this *MyCircularDeque) InsertFront(value int) bool {
	if this.IsFull() {
		return false
	}

	if this.left >= 0 {
		this.queue[this.left%this.capability] = value
	} else { // left是负数，所以做加法
		this.queue[this.left%this.capability+this.capability] = value
	}

	this.left-- // 一个指针后移动，即添加完数据再移动
	return true
}

func (this *MyCircularDeque) InsertLast(value int) bool {
	if this.IsFull() {
		return false
	}

	this.right++ // 一个指针先移动，即先移动再添加数据

	if this.right >= 0 {
		this.queue[this.right%this.capability] = value
	} else { // right是负数，所以做加法
		this.queue[this.right%this.capability+this.capability] = value
	}

	return true
}

func (this *MyCircularDeque) DeleteFront() bool {
	if this.IsEmpty() {
		return false
	}

	this.left++
	return true
}

func (this *MyCircularDeque) DeleteLast() bool {
	if this.IsEmpty() {
		return false
	}

	this.right--
	return true
}

func (this *MyCircularDeque) GetFront() int {
	if this.IsEmpty() {
		return -1
	}

	if this.left+1 >= 0 { // left是先添加数据再移动向左的，所以需要加1
		return this.queue[(this.left+1)%this.capability]
	} else {
		return this.queue[(this.left+1)%this.capability+this.capability]
	}
}

func (this *MyCircularDeque) GetRear() int {
	if this.IsEmpty() {
		return -1
	}

	if this.right >= 0 { // right就是代表当前值的下标，所以不需要加1或减1
		return this.queue[this.right%this.capability]
	} else {
		return this.queue[this.right%this.capability+this.capability]
	}
}

func (this *MyCircularDeque) IsEmpty() bool {
	return this.right == this.left // 两值相等就为空
}

func (this *MyCircularDeque) IsFull() bool {
	return this.right-this.left == this.capability // 相减等于容量就满了
}

/**
 * Your MyCircularDeque object will be instantiated and called as such:
 * obj := Constructor(k);
 * param_1 := obj.InsertFront(value);
 * param_2 := obj.InsertLast(value);
 * param_3 := obj.DeleteFront();
 * param_4 := obj.DeleteLast();
 * param_5 := obj.GetFront();
 * param_6 := obj.GetRear();
 * param_7 := obj.IsEmpty();
 * param_8 := obj.IsFull();
 */
// @lc code=end

